<script setup lang="ts">
import { ref, computed, watch, onBeforeUnmount } from 'vue'
import { ElMessage } from 'element-plus'
import { Plus, CircleX, Play, SquarePlay } from '@vben/icons'
import { $t } from '@vben/locales'
import { uploadVideoWithChunks, isVideoFile, getVideoDuration, formatDuration, calculateOptimalChunkSize, formatFileSize } from '#/utils/videoUpload'
import { obsDelete, obsDownload } from '#/utils/obs'
import { useVodPlayer } from '#/hooks/useVodPlayer'

defineOptions({ name: 'UploadVideo' })

interface UploadFileItem { name: string }

const props = withDefaults(defineProps<{
  modelValue?: string | ''
  accept?: string
  maxSize?: number
  disabled?: boolean
  removable?: boolean
  deleteRemote?: boolean // 默认不删除远端
  buttonText?: string
  formatTip?: string
  showProgress?: boolean
  showPreview?: boolean
  stylePreview?: string
  videoType?: 'obs' | 'vod' | 'url' | 'auto' // 视频类型：OBS存储、VOD媒资、直接URL、自动检测
  vodAssetId?: string // VOD媒资ID（当videoType为vod时使用）
}>(), {
  accept: '.mp4,.wmv,.avi,.mov,.flv,.rmvb,.3gp,.m4v,.mkv',
  maxSize: 5 * 1024 * 1024 * 1024,
  disabled: false,
  removable: true,
  deleteRemote: false,
  buttonText: '',
  formatTip: '',
  showProgress: true,
  showPreview: true,
  stylePreview: '',
  videoType: 'auto',
  vodAssetId: '',
})

const emit = defineEmits<{
  'update:modelValue': [value: string | '']
  'success': [path: string]
  'error': [error: any]
  'progress': [percent: number]
  'remove': []
}>()

// VOD播放器hook
const {
  getPlayInfo,
  getBestPlayUrl,
} = useVodPlayer()

// 内部状态
const uploadRef = ref()
const fileList = ref<UploadFileItem[]>([])
const path = ref<string>('')
const uploadProgress = ref(0)
const isUploading = ref(false)
const videoDuration = ref('')
const videoUrl = ref('')
const isPlaying = ref(false)
const videoRef = ref<HTMLVideoElement | null>(null)
const currentUploadController = ref<AbortController | null>(null)
const isVideoLoading = ref(false)
const videoLoadError = ref(false)
const previewVideoUrl = ref('')
const currentVideoType = ref<'obs' | 'vod' | 'url'>('url')

const getSelectButtonText = computed(() => props.buttonText || $t('course.selectVideo'))
const getFileFormatTip = computed(() => props.formatTip || $t('course.videoFileFormatTip'))
const getUploadProgressText = computed(() => $t('course.videoUploadProgress', [uploadProgress.value]))
const getUploadSuccessText = computed(() => $t('course.videoUploadSuccess'))
const getUploadFailedText = computed(() => $t('course.videoUploadFailed'))

// 视频类型检测
const detectVideoType = (url: string): 'obs' | 'vod' | 'url' => {
  if (!url) return 'url'

  // 如果明确指定了类型，使用指定的类型
  if (props.videoType !== 'auto') {
    return props.videoType as 'obs' | 'vod' | 'url'
  }

  // 自动检测逻辑
  if (props.vodAssetId) {
    return 'vod'
  }

  // 检测是否为HTTP/HTTPS URL
  if (url.startsWith('http://') || url.startsWith('https://')) {
    return 'url'
  }

  // 检测是否为OBS路径（通常不包含协议，可能包含路径分隔符）
  if (url.includes('/') && !url.startsWith('http')) {
    return 'obs'
  }

  // 默认为直接URL
  return 'url'
}

// 加载OBS视频
const loadObsVideo = async (obsKey: string) => {
  isVideoLoading.value = true
  videoLoadError.value = false

  try {
    await new Promise<void>((resolve, reject) => {
      obsDownload({
        Key: obsKey,
      }, (err: any, result: any) => {
        if (err) {
          // console.error('获取OBS视频失败:', err)
          reject(err)
          return
        }

        // 创建视频URL
        if (result.InterfaceResult?.Content) {
          const content = result.InterfaceResult.Content as ArrayBuffer
          const blob = new Blob([content], { type: 'video/mp4' })
          // 清理之前的Blob URL（如果存在）
          if (previewVideoUrl.value && previewVideoUrl.value.startsWith('blob:')) {
            URL.revokeObjectURL(previewVideoUrl.value)
          }
          previewVideoUrl.value = window.URL.createObjectURL(blob)
          resolve()
        } else {
          reject(new Error('OBS视频内容为空'))
        }
      })
    })
  } catch (error) {
    // console.error('加载OBS视频失败:', error)
    videoLoadError.value = true
  } finally {
    isVideoLoading.value = false
  }
}

// 加载VOD视频
const loadVodVideo = async (assetId: string) => {
  isVideoLoading.value = true
  videoLoadError.value = false

  try {
    const info = await getPlayInfo(assetId)
    if (info && info.playUrls.length > 0) {
      const bestUrl = getBestPlayUrl(info)
      previewVideoUrl.value = bestUrl
    } else {
      throw new Error('VOD播放信息为空')
    }
  } catch (error) {
    // console.error('加载VOD视频失败:', error)
    videoLoadError.value = true
  } finally {
    isVideoLoading.value = false
  }
}

// 加载直接URL视频
const loadUrlVideo = (url: string) => {
  videoLoadError.value = false
  previewVideoUrl.value = url
  // 对于直接URL，让video元素自己处理加载状态
  // 不在这里设置isVideoLoading，而是通过video事件处理
}

// 统一视频加载入口
const loadVideoPreview = async (url: string) => {
  if (!url) {
    previewVideoUrl.value = ''
    return
  }

  const videoType = detectVideoType(url)
  currentVideoType.value = videoType

  switch (videoType) {
    case 'obs':
      await loadObsVideo(url)
      break
    case 'vod':
      await loadVodVideo(props.vodAssetId || url)
      break
    case 'url':
    default:
      loadUrlVideo(url)
      break
  }
}

const handleSelectFile = () => {
  if (props.disabled) return
  if (fileList.value.length > 0) {
    ElMessage.error($t('course.deleteFileTip'))
    return
  }
  const inputElement = uploadRef.value?.$el?.querySelector?.('input[type="file"]')
  inputElement && inputElement.click()
}

// 校验
const beforeUpload = async (file: File) => {
  if (fileList.value.length > 0) {
    ElMessage.error($t('course.deleteFileTip'))
    return false
  }
  const allowed = isVideoFile(file)
  if (!allowed) {
    ElMessage.error($t('仅支持视频文件格式'))
    return false
  }
  if (file.size > props.maxSize) {
    ElMessage.error($t('视频大小不能超过{0}', [formatFileSize(props.maxSize)]))
    return false
  }
  try {
    const duration = await getVideoDuration(file)
    videoDuration.value = formatDuration(duration)
    // 清理之前的videoUrl（如果存在）
    if (videoUrl.value) {
      URL.revokeObjectURL(videoUrl.value)
    }
    videoUrl.value = URL.createObjectURL(file)
    // 本地文件预览使用 videoUrl
    previewVideoUrl.value = videoUrl.value
    currentVideoType.value = 'url'
    videoLoadError.value = false
  } catch (e) {
    // 忽略获取时长失败
  }
  return true
}

// 上传
const handleUpload = async ({ file }: any) => {

  isUploading.value = true
  uploadProgress.value = 0
  currentUploadController.value = new AbortController()

  try {
    const optimalChunkSize = calculateOptimalChunkSize(file.size)
    await uploadVideoWithChunks({
      file,
      chunkSize: optimalChunkSize,
      signal: currentUploadController.value.signal,
      onProgress: (p) => { uploadProgress.value = p; emit('progress', p) },
      onSuccess: (p) => {
        path.value = p
        emit('update:modelValue', p)
        emit('success', p)
        isUploading.value = false
        uploadProgress.value = 100
        ElMessage.success(getUploadSuccessText.value)
        resetUploaderDom()
      },
      onError: (err) => {
        isUploading.value = false
        uploadProgress.value = 0
        // 取消不提示错误
        if (String(err?.message || '').includes('已取消')) return
        ElMessage.error(getUploadFailedText.value)
        emit('error', err)
      }
    })
  } catch (err) {
    isUploading.value = false
    uploadProgress.value = 0
    if (!String((err as any)?.message || '').includes('已取消')) {
      ElMessage.error(getUploadFailedText.value)
      emit('error', err)
    }
  }
}

// 删除
const removeFile = async () => {
  // 不默认删除远端，除非显式开启 deleteRemote
  if (props.deleteRemote && path.value) {
    try {
      await new Promise((resolve, reject) => {
        obsDelete({ Key: path.value }, (err: any) => err ? reject(err) : resolve(true))
      })
    } catch { }
  }
  cleanupVideoResources()
  resetUploaderDom()
  path.value = ''
  fileList.value = []
  isUploading.value = false
  uploadProgress.value = 0
  emit('update:modelValue', '')
  emit('remove')
}

// 取消上传
const cancelUpload = () => {
  if (currentUploadController.value) {
    currentUploadController.value.abort()
    currentUploadController.value = null
  }
  isUploading.value = false
  uploadProgress.value = 0
  resetUploaderDom()
  ElMessage.info($t('common.cancelTxt'))
}

// 播放控制
const toggleVideo = async () => {
  const v = videoRef.value
  if (!v) return
  try {
    if (isPlaying.value) { v.pause(); isPlaying.value = false }
    else { await v.play(); isPlaying.value = true }
  } catch (e) {
    isPlaying.value = false
    ElMessage.error('视频播放失败，请检查视频文件是否有效')
  }
}

const onVideoPlay = () => isPlaying.value = true
const onVideoPause = () => isPlaying.value = false
const onVideoError = () => {
  isPlaying.value = false
  videoLoadError.value = true
  isVideoLoading.value = false
  // ElMessage.error('视频加载失败，请检查视频文件格式')
}

// 视频加载状态处理
const onVideoLoadStart = () => {
  if (currentVideoType.value === 'url') {
    isVideoLoading.value = true
    videoLoadError.value = false
  }
}

const onVideoLoadedData = () => {
  if (currentVideoType.value === 'url') {
    isVideoLoading.value = false
    videoLoadError.value = false
  }
}

const onVideoCanPlay = () => {
  if (currentVideoType.value === 'url') {
    isVideoLoading.value = false
  }
}

function cleanupVideoResources() {
  if (videoRef.value) {
    try { videoRef.value.pause(); videoRef.value.currentTime = 0 } catch { }
  }
  if (videoUrl.value) { URL.revokeObjectURL(videoUrl.value); videoUrl.value = '' }
  // 清理预览URL（如果是Blob URL）
  if (previewVideoUrl.value && previewVideoUrl.value.startsWith('blob:')) {
    URL.revokeObjectURL(previewVideoUrl.value)
  }
  isPlaying.value = false
  videoDuration.value = ''
  previewVideoUrl.value = ''
  isVideoLoading.value = false
  videoLoadError.value = false
  currentVideoType.value = 'url'
  if (currentUploadController.value) { currentUploadController.value.abort(); currentUploadController.value = null }
}

function resetUploaderDom() {
  const uploader = uploadRef.value
  try { uploader?.clearFiles?.() } catch {}
  const input: HTMLInputElement | null =
    uploader?.$el?.querySelector?.('input[type="file"]') ?? null
  if (input) input.value = ''
}

// 初始化：根据 v-model 回显，并加载视频预览
watch(() => props.modelValue, async (val) => {
  path.value = val || ''
  if (val) {
    const name = val.split('/').pop() || val
    fileList.value = [{ name }]
    // 加载视频预览，添加错误处理
    try {
      await loadVideoPreview(val)
    } catch (error) {
      // console.error('加载视频预览失败:', error)
      videoLoadError.value = true
      isVideoLoading.value = false
    }
  } else {
    fileList.value = []
    previewVideoUrl.value = ''
    videoLoadError.value = false
    isVideoLoading.value = false
  }
}, { immediate: true })

onBeforeUnmount(() => cleanupVideoResources())

defineExpose({
  isUploading,
})

</script>

<template>
  <div class="w-full">
    <!-- 隐藏的上传组件 -->
    <el-upload ref="uploadRef" class="hidden-upload" action="#" :accept="accept" :http-request="handleUpload"
      :before-upload="beforeUpload" :limit="1" :auto-upload="true" :show-file-list="false" style="display:none" />

    <!-- 点击上传 有视频则不显示 -->
    <div class="flex items-center pointer-cursor" @click="handleSelectFile" v-if="!(fileList.length > 0 || path)">
      <slot name="upload-btn">
        <el-button :icon="Plus" :disabled="disabled">{{ getSelectButtonText }}</el-button>
        <div class="text-xs text-gray-500 ml-2">{{ getFileFormatTip }}</div>
      </slot>
    </div>

    <!-- 进度 -->
    <div v-if="showProgress && isUploading" class="mt-3 w-full">
      <div class="flex items-center justify-between mb-2">
        <span class="text-sm text-gray-600">{{ $t('course.videoUploading') }}</span>
        <div class="flex items-center space-x-2">
          <span class="text-sm text-blue-600">{{ getUploadProgressText }}</span>
          <el-button size="small" type="danger" @click="cancelUpload">{{ $t('common.cancelTxt') }}</el-button>
        </div>
      </div>
      <el-progress :percentage="uploadProgress" :show-text="false" />
    </div>

    <!-- 文件卡片与预览 -->
    <div v-if="fileList.length > 0 || path" class="mt-3 w-full" :style="stylePreview">
      <div class="px-3 py-2 bg-[#F2F7FD] rounded-md w-[95%]">
        <div class="flex items-center justify-between">
          <div class="flex items-center">
            <el-icon class="text-blue-500 mr-2">
              <SquarePlay />
            </el-icon>
            <div class="flex flex-col">
              <span class="text-sm text-gray-700">{{ (fileList[0] && fileList[0].name) || (path &&
                path.split('/').pop()) }}</span>
              <span v-if="videoDuration" class="text-xs text-gray-500">{{ $t('course.videoDuration', [videoDuration])
              }}</span>
            </div>
          </div>
          <el-button v-if="removable" size="small" :icon="CircleX" link @click="removeFile" />
        </div>

        <!-- 视频预览 - 支持本地文件、OBS存储、VOD媒资和远程URL -->
        <div v-if="showPreview && previewVideoUrl" class="mt-3">
          <div class="relative bg-black rounded-md overflow-hidden" style="aspect-ratio:16/9;">
            <!-- 加载状态 -->
            <div v-if="isVideoLoading" class="absolute inset-0 flex items-center justify-center bg-black bg-opacity-50">
              <div class="flex flex-col items-center text-white">
                <div class="loading-spinner mb-2"></div>
                <span class="text-sm">{{ $t('course.videoUploading') }}</span>
              </div>
            </div>

            <!-- 加载失败状态 -->
            <div v-else-if="videoLoadError" class="absolute inset-0 flex items-center justify-center bg-gray-100">
              <div class="flex flex-col items-center text-gray-500">
                <el-icon class="text-3xl mb-2">
                  <CircleX />
                </el-icon>
                <span class="text-sm">{{ getUploadFailedText }}</span>
              </div>
            </div>

            <!-- 视频播放器 -->
            <video v-else ref="videoRef" :src="previewVideoUrl" class="w-full h-full object-contain" controls preload="metadata"
              @play="onVideoPlay"
              @pause="onVideoPause"
              @error="onVideoError"
              @loadstart="onVideoLoadStart"
              @loadeddata="onVideoLoadedData"
              @canplay="onVideoCanPlay">
              {{ $t('course.unsupportedVideoFormat') }}
            </video>

            <!-- 播放按钮覆盖层 -->
            <div v-if="!isPlaying && !isVideoLoading && !videoLoadError"
              class="absolute inset-0 flex items-center justify-center bg-black bg-opacity-30 cursor-pointer"
              @click="toggleVideo">
              <el-icon class="text-white text-4xl">
                <Play />
              </el-icon>
            </div>
          </div>

          <!-- 播放控制按钮 -->
          <div v-if="!videoLoadError" class="flex items-center justify-center mt-2">
            <el-button size="small" :icon="isPlaying ? SquarePlay : Play" @click="toggleVideo" :disabled="isVideoLoading">
              {{ isPlaying ? $t('course.pauseVideo') : $t('course.playVideo') }}
            </el-button>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<style scoped>
.hidden-upload {
  display: none !important;
  visibility: hidden !important;
  pointer-events: none !important;
  position: absolute !important;
  left: -9999px !important
}

.loading-spinner {
  width: 24px;
  height: 24px;
  border: 2px solid rgba(255, 255, 255, 0.3);
  border-top: 2px solid #ffffff;
  border-radius: 50%;
  animation: spin 1s linear infinite;
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
</style>
